import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.util.StringTokenizer;


/*****************************************************************************
 * File: Agent.java
 * Author:  Todd Silvia & Phil Pilosi
 * Class:   CS 441 - Spring 2011
 * Project: 2 - Distributed Booking Agent, with RMI
 * Date:    February 28th 2011
 * Description: This class holds all of the functionality for an Agent client.
 * 				This handles the input from the user and calls the relevant
 * 				server/rmi commands.
 */

public class Agent {
	private BufferedReader keyboardIn;
	ServerFunc myRemote;						//Object reference to the rmi/server functions
	ClientCallbackInterface clientRemote;
	
	public Agent() {
		keyboardIn = new BufferedReader(new InputStreamReader(System.in));
	}
	
	public void newMain(String[] args)
	{
		//Welcome user!
		this.welcomeMessage();
		//Setup RMI stuffs
		this.startConnection();
		//Wait for input function!
		try
		{
			this.waitForCommand();
		}
		catch(Exception e)
		{
			System.out.println("Error: " + e);
		}
		//this.waitForCommand();


	}//END newMain()

	public static void main(String[] args)
	{
		Agent newAgent = new Agent();
		newAgent.newMain(args);
	}//END main()

	public void welcomeMessage()
	{
		System.out.println("");
	}//END welcomeMessage

	/*****************************************************************************
	 * Connects to the rmi and sets up any connection criteria.
	 */
	public void startConnection() 
	{
		String serverName = "127.0.0.1";
		String portNum = ":13337";

		String rmiName = "rmi://" + serverName + portNum +"/dataServer";	

		System.out.println("Connecting to data server");
	
		try
		{
			myRemote = (ServerFunc)Naming.lookup(rmiName);//Test successful!
			//System.out.println("<dflag>Client should be pseudo committed for testing.");//<dflag> 
			
			clientRemote = new ClientCallbackImp();			
			
			//Given this is the manager after making connection should invoke the Server.connect()
			//method.
			//myRemote.connect(clientRemote); //<dflag>Test call! 

		}
		catch(Exception e)
		{
			System.out.println("Error: " + e);

			System.out.println("Program shutting down, due to failing to connect to server");
			System.out.println("Please restart the application and try again.");
			System.out.println("If the problem continues, please call the system administrator");
			System.out.println("of your server to resolve the issue");
			System.exit(-1);
		}

		
	}//END startConnection()
	
	/*****************************************************************************
	 * Waits for the user to enter a command to determine the action to be taken 
	 * by the client. Also checks for proper input, e.g. NumberFormatException and
	 * not enough arguments
	 */
	public void waitForCommand() throws IOException {
		while ( true ) {
			int eventNumber = 0;
			//Read in command from the user
			String commandEntered = keyboardIn.readLine();
			StringTokenizer strTok = new StringTokenizer(commandEntered);
			if(strTok.hasMoreTokens()) {
				String command1 = strTok.nextToken();
				
				//If the user wants to view all events on the server
				if(command1.equalsIgnoreCase("view")) {
					viewEvents();
				//The suer wants to reserve space in an event
				} else if( command1.equalsIgnoreCase("reserve")) {
					int spaceTaken;
					if(strTok.countTokens() != 3) {
						System.out.println("You did not enter the proper number of arguments!");
						continue;
					}
					try {
						eventNumber = Integer.parseInt(strTok.nextToken().trim());
						spaceTaken = Integer.parseInt(strTok.nextToken().trim());
					} catch (NumberFormatException e) {
						System.out.println("You did not enter a numerical number correctly!");
						continue;
					}
					String theName = strTok.nextToken();
					if(theName.length() < 1) {
						System.out.println("You did not enter a valid name length!");
						continue;
					}
					makeReservation(eventNumber, spaceTaken, theName);
				
				//User wants to delete a reservation from an event
				} else if(command1.equalsIgnoreCase("delete")) {
					int confirmationNumber;
					if(strTok.countTokens() != 2) {
						System.out.println("You did not enter proper number of arguments!");
						continue;
					}
					try {
						eventNumber = Integer.parseInt(strTok.nextToken().trim());
						confirmationNumber = Integer.parseInt(strTok.nextToken().trim());
					}catch (NumberFormatException e) {
						System.out.println("You did not enter a numerical number correctly!");
						continue;
					}
					deleteReservation(eventNumber, confirmationNumber);
					
				//User wants to exit their session
				} else if(command1.equalsIgnoreCase("exit")) {
					terminateClient();
				} else {
					System.out.println("That command is not recognized!");
				}
			}
		}
	}//END waitForCommand()
	
	/*****************************************************************************
	 * The list of all current events in the database are returned to the user and
	 * displayed
	 */
	public void viewEvents() {
		PacketContainer tempRecieved = null;
		try {
			tempRecieved = (PacketContainer)myRemote.viewEvents();
		} catch (RemoteException e) {
			e.printStackTrace();
			return;
		}
		
		if( tempRecieved != null ) {
			
			if(tempRecieved.getListEvents().size() == 0) {
				System.out.println("There are no events to view!");
				return;
			}
			//Display all of the events in the terminal
			for(int i = 0; i < tempRecieved.getListEvents().size(); i++) {
				System.out.print("Event Number: " + tempRecieved.getListEvents().get(i).getEventNumber() + "\nDescription: " + 
						tempRecieved.getListEvents().get(i).getEventDescription() + "\nAvailable Space: " + 
						tempRecieved.getListEvents().get(i).getSpaceRemaining() + "\nTotal Space: " +  tempRecieved.getListEvents().get(i).getEventSpace() +"\n\n");
			}
		}
	}//END viewEvents()
	
	/*****************************************************************************
	 * The user enters the event number, space to reserve, and a name to attach
	 * to the reservation. If the event number is valid, and the amount of space
	 * doesn't ask for more then available then the reservation is added to the
	 * event on the server.
	 */
	public void makeReservation(int theEventNumber, int theSpaceRequested, String theName)
	{
		PacketContainer tempRecieved = null;
		try {
			tempRecieved = (PacketContainer)myRemote.makeReservation(theEventNumber, theSpaceRequested, theName);
		} catch (RemoteException e) {
			e.printStackTrace();
			return;
		}
		
		if( tempRecieved != null ) {
			if(tempRecieved.getPacketNumber() != 0) {
				//The reservation was added, and the confirmation number is printed to the screen
				System.out.println("Confirmation Number: " + tempRecieved.getPacketNumber());
			} else {
				System.out.println("There was not enough space or the event number you entered was not valid!");
			}
		} 
	}//END makeReservation()
	
	/*****************************************************************************
	 * User enters an event number, and a confirmation number. If both are found
	 * to be valid the reservation is displayed to the user. If they confirm the 
	 * deletion then the reservation is removed from the event and the spaces are
	 * freed to the corresponding event.
	 */
	public void deleteReservation(int theEventNumber, int theConfirmationNumber) throws IOException {
		PacketContainer tempRecieved = null;
		try {
			tempRecieved = (PacketContainer)myRemote.askReservation(theEventNumber, theConfirmationNumber);
		} catch (RemoteException e) {
			e.printStackTrace();
			return;
		}
		
		if( tempRecieved != null ) {
			//Ask user for confirmation
			System.out.print("Are you sure you want to delete reservation:" + "\nName: " + tempRecieved.getPacketReservation().getNameForReservation() +
							"\nSpace Reserved: " + tempRecieved.getPacketReservation().getSpaceReserved() + "\n(Yes or No)? ");
			
			String yesNo = keyboardIn.readLine();
			if(yesNo.compareToIgnoreCase("yes") == 0) {
				//User confirmed deletion
				tempRecieved = (PacketContainer)myRemote.deleteReservation(theEventNumber, theConfirmationNumber);
				
				if(tempRecieved != null ) {
					if(tempRecieved.getPacketNumber() != 0) {
						//Server responds saying that the reservation was indeed removed
						System.out.println("The reservation was removed from the database!");
					}
				} else {
					System.out.println("There was an error removing the reservation from the server!");
				}
			}
		} else {
			System.out.println("The event number and confirmation number were not found!");
		}
	}//END deleteReservation()
	
	/*****************************************************************************
	 * Simply closes the connection and ends the client program.
	 */
	public void terminateClient() {
		System.out.println("Manager shutting down");
		System.out.println("Requesting to be removed from Server broadcast");


		System.out.println("Program ending");
		System.exit(0);
	}//END terminateClient()
	
	
}//END Agent{}
